/**
 * @filename:InventoryServiceImpl Dec 11, 2023
 * @project Wonder Vue Admin Api  1.1.0
 * Copyright(c) 2022 Wonder Co. Ltd.
 * All right reserved.
 */
package com.wonder.app.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.io.FileUtil;
import cn.hutool.json.JSONObject;
import com.vtuzx.core.VtuzxException;
import com.vtuzx.core.bean.dto.VtuzxMap;
import com.vtuzx.core.utils.VtuzxUtil;
import com.wonder.app.domain.InStock;
import com.wonder.app.domain.Inventory;
import com.wonder.app.domain.Inventorylog;
import com.wonder.app.domain.StockList;
import com.wonder.app.mapper.InventoryDao;
import com.wonder.app.mapper.InventorylogDao;
import com.wonder.app.mapper.StockListDao;
import com.wonder.app.request.PlusRequest;
import com.wonder.app.service.InventoryService;
import com.wonder.app.request.InventoryRequest;
import com.wonder.bean.kingdee.xqc.BillMaterial;
import com.wonder.common.utils.DateUtils;
import com.wonder.common.utils.StringUtils;
import com.wonder.common.utils.MessageUtils;
import com.wonder.common.common.AjaxResult;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;

import com.wonder.common.utils.file.FileUtils;
import com.wonder.constant.BillEvent;
import com.wonder.constant.BillType;
import com.wonder.constant.IXqcConst;
import org.apache.ibatis.session.SqlSession;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

/**
 * @Description:TODO(即时库存服务实现)
 *
 * @version: 1.1.0
 * @author: Wonder
 *
 */
@Service
public class InventoryServiceImpl  extends ServiceImpl<InventoryDao, Inventory> implements InventoryService  {

    /**
     * Logger
     */
    private static final Logger _logger = LoggerFactory.getLogger(InventoryServiceImpl.class);


    @Autowired
    private InventoryDao inventoryDao;

    @Autowired
    private InventorylogDao inventorylogDao;

    @Autowired
    private InventoryService inventoryService;
    /**
     * 验证即时库存信息
     *
     * @param inventory
     * @param type
     * @return String
     */
    @Override
    public String validate(Inventory inventory,String type){


        return "";
    }


    /**
     * Description:即时库存分页返回
     * @param request //检索条件
     * @param page //分页参数
     * @return IPage<Inventory>   //分页记录
     */
    @Override
    public IPage<Inventory> selectList(InventoryRequest request, Page<Inventory> page){
        LambdaQueryWrapper<Inventory> lambdaQueryWrapper = new LambdaQueryWrapper<>();

        if (null != request.getId()) {
            lambdaQueryWrapper.eq(Inventory::getId, request.getId());
        }
        if (null != request.getFmaterialNumber() ){
            lambdaQueryWrapper.like(Inventory::getFMaterialNumber, request.getFmaterialNumber());
        }

        if (null != request.getFlot() ){
            lambdaQueryWrapper.like(Inventory::getFlot, request.getFlot());
        }

        if (null != request.getFstockNumber() ){
            lambdaQueryWrapper.like(Inventory::getFStockNumber, request.getFstockNumber());
        }

        if (request.getFproduceDate() != null){
            Date[] produceDate=request.getFproduceDate();
            if(produceDate.length>0)
                lambdaQueryWrapper.gt(Inventory::getFProduceDate, produceDate[0]);
            if(produceDate.length==2)
                lambdaQueryWrapper.lt(Inventory::getFProduceDate, DateUtils.setHourMinuteSecond(produceDate[1],23,59,59));

        }


        lambdaQueryWrapper.orderByDesc(Inventory::getId);
        Page<Inventory> selectPage = this.baseMapper.selectPage(page, lambdaQueryWrapper);
        return selectPage;
    }

    /**
     * 即时库存入库
     * @param userId
     * @param userName
     * @param billEvent 单据状态
     * @param billType 单据类型
     * @param billNo 单据编号
     * @param dataList 入库数据
     * @throws Exception
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String,Object> addInventory(Long userId, String userName, BillEvent billEvent, BillType billType,  String billNo, List<BillMaterial> dataList) throws Exception {
        Map<String,Object> result = new HashMap<>();
        _logger.info(String.format("即时库存入库开始:事件[%s],单据类型[%s],单号[%s]",billEvent,billType.label(),billNo));
        //sign == 1入库，== -1出库
        int sign = billType.inventoryIO();
        if (sign == 0){
            throw new VtuzxException(IXqcConst.Msg_E_XQC_stock_bill_failure, billNo, billType.label(), billEvent.label());
        }
        switch (billEvent) {
            case Audit: {
                if (sign < 0) {
                    throw new VtuzxException(IXqcConst.Msg_E_XQC_stock_event_failure, billNo, billType.label(), billEvent.label());
                }
                break;
            }
            case Unaudit: {
                if (sign > 0) {
                    throw new VtuzxException(IXqcConst.Msg_E_XQC_stock_event_failure, billNo, billType.label(), billEvent.label());
                }
                break;
            }
            default: {
                throw new VtuzxException(IXqcConst.Msg_E_XQC_stock_event_failure, billNo, billType.label(), billEvent.label());
            }
        }

        _logger.info(String.format("即时库存入库事务启动: 事件[%s], 单据类型[%s], 单号[%s]", billEvent.label(), billType.label(), billNo));
        try {
            for (BillMaterial material : dataList){
                String stockNo = material.getStockNo();
                _logger.info(String.format("物料即时库存入库: 单号[%s], 物料[%s],仓库[%s]", billNo, material.getMaterialNo(),stockNo));
                addInventoryMaterial(userName,stockNo,billEvent,billType,billNo,material);
            }
            _logger.info(String.format("即时库存入库事务完成: 事件[%s], 单据类型[%s], 单号[%s]", billEvent.label(), billType.label(), billNo));
        } catch (Exception e){
            _logger.warn(String.format("即时库存入库异常: 事件[%s], 单据类型[%s], 单号[%s], %s", billEvent.label(), billType.label(), billNo, e.getMessage()), e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            _logger.info(String.format("即时库存入库回滚完成: 事件[%s], 单据类型[%s], 单号[%s]", billEvent.label(), billType.label(), billNo));
            result.put("status",false);
            result.put("msg",e.getMessage());
            return result;
//			throw e;

        }
        result.put("status",true);

        return result;
    }

    /**
     * 即时库存出库
     * @param userId
     * @param userName
     * @param billEvent
     * @param billType
     * @param billNo
     * @param dataList
     * @throws Exception
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String,Object> reduceInventory(Long userId, String userName, BillEvent billEvent, BillType billType,  String billNo, List<BillMaterial> dataList) throws Exception {
        Map<String,Object> result = new HashMap<>();
        _logger.info(String.format("即时库存出库开始:事件[%s],单据类型[%s],单号[%s]",billEvent,billType.label(),billNo));
        //sing == 1入库，== -1出库
        int sign = billType.inventoryIO();
        if (sign == 0) {
            throw new VtuzxException(IXqcConst.Msg_E_XQC_stock_out_bill_failure, billNo, billType.label(), billEvent.label());
        }
        switch (billEvent)
        {
            case Audit: {
                if (sign > 0) {
                    throw new VtuzxException(IXqcConst.Msg_E_XQC_stock_out_event_failure, billNo, billType.label(), billEvent.label());
                }
                break;
            }
            case Unaudit: {
                if (sign < 0) {
                    throw new VtuzxException(IXqcConst.Msg_E_XQC_stock_out_event_failure, billNo, billType.label(), billEvent.label());
                }
                break;
            }
            default: {
                throw new VtuzxException(IXqcConst.Msg_E_XQC_stock_out_event_failure, billNo, billType.label(), billEvent.label());
            }
        }
        try {
            for (BillMaterial material : dataList){
                String stockNo = material.getStockNo();
                _logger.info(String.format("物料即时库存出库: 单号[%s], 物料[%s],仓库[%s]", billNo, material.getMaterialNo(),stockNo));
                reduceInventoryMaterial(userName,stockNo,billEvent,billType,billNo,material);
            }
            _logger.info(String.format("即时库存出库事务完成: 事件[%s], 单据类型[%s], 单号[%s]", billEvent.label(), billType.label(), billNo));
        } catch (Exception e){
            _logger.warn(String.format("即时库存出库异常: 事件[%s], 单据类型[%s], 单号[%s], %s", billEvent.label(), billType.label(), billNo, e.getMessage()), e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            _logger.info(String.format("即时库存出库回滚完成: 事件[%s], 单据类型[%s], 单号[%s]", billEvent.label(), billType.label(), billNo));
            result.put("status",false);
            result.put("msg",e);
            return result;
//			throw e;
        }

        result.put("status",true);
        return result;
    }

    @Override
    public boolean readInventory(JSONObject map) throws Exception{
        File file = new File("C:/Users/87958/Desktop/秒和期初库存.xlsx");
        InputStream inputStream = new FileInputStream(file);
        Workbook workbook = new XSSFWorkbook(inputStream);
        Sheet sheet = workbook.getSheetAt(0);

        int rowSize =  sheet.getLastRowNum();

        List<Inventory> inventoryList = new ArrayList<>();
        for (int ci = sheet.getFirstRowNum() + 1;ci <= rowSize;ci++){
            Row row = sheet.getRow(ci);
            String stockNo = FileUtils.getCellValue(row.getCell(0));//仓库编号
            String stockName = FileUtils.getCellValue(row.getCell(1));//仓库名称
            String batchNo = FileUtils.getCellValue(row.getCell(2));//批号
//            String produceDate = FileUtils.getCellValue(row.getCell(3));//生产日期
//            if (row.getCell(3).getDateCellValue() != null){
//                SimpleDateFormat sda = new SimpleDateFormat("yyyy-MM-dd");
//                String value = sda.format(row.getCell(3).getDateCellValue());
//                System.out.println(value);
//            }
            String materialNo = FileUtils.getCellValue(row.getCell(4));//物料编码
            String materialName = FileUtils.getCellValue(row.getCell(5));//物料名称
            String specification = FileUtils.getCellValue(row.getCell(6));//规格
            String unit = FileUtils.getCellValue(row.getCell(7));//规格
            Double  useCount = Double.parseDouble(FileUtils.getCellValue(row.getCell(8)));//岗上数量
            Double  count = Double.parseDouble(FileUtils.getCellValue(row.getCell(9)));//数量
//            String remark = FileUtils.getCellValue(row.getCell(9));//备注
            Inventory inventory = new Inventory();
            inventory.setFStockNumber(stockNo);
            inventory.setFStockName(stockName);
            inventory.setFlot(batchNo);
//            inventory.setFProduceDate(DateUtils.strToDate(produceDate,""));
            inventory.setFMaterialNumber(materialNo);
            inventory.setFMaterialName(materialName);
            inventory.setFSpecification(specification);
            inventory.setFunit(unit);
            inventory.setFqty(count);
            inventory.setUseCount(useCount);
            inventory.setIsProduce(false);
            inventory.setIsFlot(false);
//            inventory.setRemark(remark);
            inventoryList.add(inventory);
        }
        //向数据库添加数据
        boolean b = inventoryService.saveBatch(inventoryList);
        System.out.println(b);


        return false;
    }


    //即时库存物料入库
    private void addInventoryMaterial(String userName,String stockNo,BillEvent billEvent,BillType billType,String billNo,BillMaterial material){
        //查询库存当前物料
        QueryWrapper<Inventory> wrapper = new QueryWrapper<>();
        wrapper.and(w -> w.eq("FStockNumber",material.getStockNo())
                .eq("FMaterialNumber",material.getMaterialNo()));
        //判断有没有启用批次和保质期
        boolean isFlot = material.getFlot();
        boolean isProduce = material.getProduce();
        if (isFlot){
            wrapper.eq("Flot",material.getBatchNo());
        }
        if (isProduce){
            String dateStr = DateUtils.dateToStr(material.getProduceDate(), DateUtils.YYYY_MM_DD);
            wrapper.eq("FProduceDate",dateStr);
        }
        //如果仓库是岗上仓库,查询的时候带上车间
        if("00".equals(material.getStockNo())){
            wrapper.eq("workShop",material.getWorkShop());
        }
        Inventory inventory = inventoryDao.selectOne(wrapper);
        Integer inventoryId = 0;//即时库存表id
        //如果为空的话做新增，不为空的话添加数量
        if (inventory == null){
            //新增的数据
            Inventory addInventory = new Inventory();
            addInventory.setFMaterialName(material.getMaterialName());
            addInventory.setFlot(material.getBatchNo());
            addInventory.setFSpecification(material.getMaterialModel());
            addInventory.setFExpiryDate(material.getExpiryDate());
            addInventory.setFMaterialNumber(material.getMaterialNo());
            addInventory.setFStockNumber(material.getStockNo());
            //如果调入的仓库是岗上仓库,加上一个车间字段
            if("00".equals(material.getMaterialNo())){
                addInventory.setWorkShop(material.getWorkShop());
            }
            addInventory.setFStockName(material.getStockName());
            addInventory.setFqty(material.getCount());
            addInventory.setFProduceDate(material.getProduceDate());//生产日期
//            addInventory.setFUpdateTime(new DateTime());//最后更新时间

            addInventory.setFunit(material.getUnit());
            addInventory.setIsFlot(material.getFlot());
            addInventory.setIsProduce(material.getProduce());
            inventoryDao.insert(addInventory);
            inventoryId = addInventory.getId();
        } else {
            double count = material.getCount();
            inventory.setFqty( inventory.getFqty() +  count);
//            inventory.setFUpdateTime(new Date());//最后修改时间
            inventory.setFProduceDate(material.getProduceDate());
            inventoryId = inventoryDao.updateById(inventory);
        }
        //增加即时库存日志表
        Inventorylog inventorylog = new Inventorylog();
        inventorylog.setFInventoryId(inventoryId);//及时库存id
        inventorylog.setFFormId(billType.label());//单据类型
        inventorylog.setFMaterialNo(material.getMaterialNo());
        inventorylog.setFBillno(billNo);
        inventorylog.setFMaterialName(material.getMaterialName());
        inventorylog.setFSPECIFICATION(material.getMaterialModel());
        inventorylog.setFUnit(material.getUnit());
        inventorylog.setFQTY(BigDecimal.valueOf(material.getCount()));
        inventorylog.setFUpdate(new Date());
        inventorylog.setFOperator(userName);
        inventorylog.setFStock(material.getStockNo());
        inventorylog.setFProduceDate(material.getProduceDate());
        inventorylog.setFExpiryDate(material.getExpiryDate());//有效期至
        inventorylog.setFLot(material.getBatchNo());
        inventorylogDao.insert(inventorylog);
    }


    //即时库存物料出库
    private void reduceInventoryMaterial(String userName,String stockNo,BillEvent billEvent,BillType billType,String billNo,BillMaterial material) throws Exception{
        //判断当前仓库是否存在该货品，并判断数量是否够出库的
        QueryWrapper<Inventory> wrapper = new QueryWrapper<>();
        wrapper.and(w -> w.eq("FStockNumber",material.getStockNo())
                .eq("FMaterialNumber",material.getMaterialNo()));

        //判断有没有启用批次和保质期
        boolean isFlot = material.getFlot();
        boolean isProduce = material.getProduce();
        if (isFlot){
            wrapper.eq("Flot",material.getBatchNo());
        }
        if (isProduce){
            String dateStr = DateUtils.dateToStr(material.getProduceDate(), DateUtils.YYYY_MM_DD);
            wrapper.eq("FProduceDate",dateStr);
        }
        //如果仓库是岗上仓库,查询的时候带上车间
        if("00".equals(material.getStockNo())){
            wrapper.eq("workShop",material.getWorkShop());
        }
        Inventory inventory = inventoryDao.selectOne(wrapper);

        if(inventory == null){
            throw new VtuzxException("货品不存在无法出库");
        } else {//判断数量
//            Double fqty = inventory.getFqty();
//            if(fqty < material.getCount()){
//                throw new VtuzxException("库存不足");
//            }
        }
        Integer inventoryId = inventory.getId();
        //扣减库存
        inventory.setFqty(inventory.getFqty() - material.getCount());
//        inventory.setFUpdateTime(new Date());
        inventory.setFProduceDate(material.getProduceDate());
        inventoryDao.updateById(inventory);
        //即时库存日志表增加记录
        Inventorylog inventorylog = new Inventorylog();
        inventorylog.setFInventoryId(inventoryId);//及时库存id
        inventorylog.setFFormId(billType.label());//单据类型
        inventorylog.setFMaterialNo(material.getMaterialNo());
        inventorylog.setFBillno(billNo);
        inventorylog.setFMaterialName(material.getMaterialName());
        inventorylog.setFSPECIFICATION(material.getMaterialModel());
        inventorylog.setFUnit(material.getUnit());
        inventorylog.setFQTY(BigDecimal.valueOf(material.getCount()).negate());//转换成负数
        inventorylog.setFUpdate(new Date());
        inventorylog.setFOperator(userName);
        inventorylog.setFStock(material.getStockNo());
        inventorylog.setFProduceDate(material.getProduceDate());
        inventorylog.setFExpiryDate(material.getExpiryDate());//有效期至
        inventorylog.setFLot(material.getBatchNo());
        inventorylogDao.insert(inventorylog);
    }
}